<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <link rel="shortcut icon" href="about:blank" type="image/vnd.microsoft.icon">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <link href="http://cdnjs.bootcss.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
        <link href="http://cdnjs.bootcss.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
        <style>
        body {
            padding-top: 60px;
        }
		
		.center {
			 margin-right: auto; 
			 margin-left: auto;
			 text-align: center;
		}
        </style>
    </head>
    
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="brand" href="#">Project name</a>
                    <div class="nav-collapse collapse">
                        <ul class="nav">
                            <li class="active"><a href="#">Home</a></li>
                            <li><a href="#about">About</a></li>
                            <li><a href="#contact">Contact</a></li>
                        </ul>
                    </div><!--/.nav-collapse -->
                </div>
            </div>
        </div>
        
        <div class="container">
            <h1>HTML5 DEMO</h1>
			<div class="span5 center">
				<canvas id="main-cv" width="400" height="300"></canvas>
			</div>
            <h2 id="msg"></h2>
            <div class="span5">
                <button id="trigger" class="btn btn-primary">Action!</button>
                <button id="reload"  class="btn btn-primary">Reload!</button>
                <label class="checkbox">
                    <input type="checkbox" id="J_nukeBoomb">NukeBoomb
                </label>
            </div>
        </div>
        
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
        <script>
        $(function () {
            var P = {
                width: 0,
                height: 0,
                cellWidth: 0,
                cellHeight: 0,
                gridWi: 0,
                gridHe: 0,
                cv: null,
                ctx: null,
                
                paintCell: function (x, y) {
                    this.ctx.fillStyle = "black";
                    this.ctx.fillRect(x*this.cellWidth, y*this.cellHeight, this.cellWidth, this.cellHeight);
                },
                
                clearCell: function (x, y) {
                    this.ctx.fillStyle = "white";
                    this.ctx.fillRect(x*this.cellWidth, y*this.cellHeight, this.cellWidth, this.cellHeight);
                },
                
                init: function (cvName, cw, ch) {
                    this.cv = $(cvName)[0];
                    this.ctx = this.cv.getContext("2d");
                    this.width = this.cv.width;
                    this.height = this.cv.height;
                    this.cellWidth = cw;
                    this.cellHeight = ch;
                    this.gridWi = this.width / cw;
                    this.gridHe = this.height / ch;
                    this.reset();
                },
				
				reset: function () {
					this.ctx.fillStyle = "white";
					this.ctx.fillRect(0, 0, this.width, this.height);
					this.ctx.strokeStyle = "black";
					this.ctx.strokeRect(0, 0, this.width, this.height);
				}
            }
            
            var CORE = {
                mtx: null,
                backmtx: null,
                wi: 0,
                he: 0,
                sz: 0,
                init: function (wi0, he0) {
                    this.wi = wi0;
                    this.he = he0;
                    this.sz = this.wi * this.he;
                },
                reset: function () {
                    this.mtx = new BitArray(this.sz, 0);
                    this.backmtx = new BitArray(this.sz, 0);
                    $('#msg').html(this.mtx.size);
                },
                get: function (x, y) {
                    if (x < 0 || y < 0 || this.wall(x, y)) return 0;
                    //has changed in current evolution loop?
                    if (this.backmtx.get(x, y) != 0) return 0;
                    return this.mtx.get(y*this.wi + x);
                },
                set: function (x, y, v) {
                    //not changed ?
                    if (v == this.get(x, y)) return;
                    var x2 = y*this.wi + x;
                    this.backmtx.set(x2, v);
                    this.mtx.set(x2, v);
                },
                setByGod: function (x, y, v) {
                    var x2 = y*this.wi + x;
                    this.mtx.set(x2, v);
                },
                wall: function (x, y) {
                    return y%this.he == 0 || x%this.wi == 0;
                },
                neighbour: function (x, y) {
                    var nb = 0;
                    for (var ix = -1; ix <= 1; ix++) {
                        for (var iy = -1; iy <= 1; iy++) {
                            if (ix == 0 && iy == 0) continue;//ignore self
                            nb += this.get(x + ix, y + iy);
                        }
                    }
                    return nb;
                },
				suicide: function (x, y) {
					for (var ix = -1; ix <= 1; ix++) {
                        for (var iy = -1; iy <= 1; iy++) {
                            this.set(x + ix, y + iy, 0);
                        }
                    }
				},
                evolute: function (x, y) {
                    var nb = this.neighbour(x, y);
					switch(nb) {
					case 2:break;
					case 3:this.set(x, y, 1);break;
					default:this.set(x, y, 0);
					}
                },
                clearBack: function (x, y) {
                    this.backmtx.clear();
                }
            };

            function loop() {
                CORE.clearBack();
				var alive = 0;
                for (var i = 0; i < CORE.he; i++) {
                    for (var j = 0; j < CORE.wi; j++) {
                        CORE.evolute(j, i);
                        if (CORE.get(j, i) == 1) {
							alive += 1;
							P.paintCell(j, i);
						}
                        else P.clearCell(j, i);
                    }
                }
				$('#msg').html(alive);
            }
            
            function initCanvas() {
                var cw = 4;
                var ch = 4;
                P.init('#main-cv', cw, ch);
                $('#msg').html('ok');       
                $('#main-cv').mousedown(function(e){
                    var x = e.pageX - this.offsetLeft;
                    var y = e.pageY - this.offsetTop;
                    var rx = Math.floor(x/cw);
                    var ry = Math.floor(y/ch);
                    if ($('#J_nukeBoomb').prop('checked') == true) {
                        for (var i = -8; i <= 8; i++) {
                            for (var j = -8; j <= 8; j++) {
                                P.clearCell(rx+j, ry+i);
                                CORE.setByGod(rx+j, ry+i, 0);
                            }
                        }
                    } else {
                        P.paintCell(rx, ry);
                        CORE.setByGod(rx, ry, 1);
                    }
                });
            }
   
            var timer = -1;
            $('#trigger').on('click', function() {
                if (timer >= 0) {
                    clearInterval(timer);
                    timer = -1;
					P.reset();
                    CORE.reset();
                } else {
                    timer = setInterval(loop, 200);
                }	
            });
            
            $('#reload').on('click', function() {
                window.location.reload(true);
            });    

            initCanvas();
            CORE.init(P.gridWi, P.gridHe);
            CORE.reset();
        });
        
        function BitArray(size, value){
            if(value === undefined) value = 0;
            this.size = size;
            this.field = new Array(~~((size - 1) / BitArray.INT_WIDTH) + 1);
            for(var i = 0; i < this.field.length; i++) 
                this.field[i] = value == 0 ? 0 : (value << BitArray.INT_WIDTH) - 1;
        }

        // will fail for values higher than 30
        BitArray.INT_WIDTH = 24;

        // Set a bit (1/0)
        BitArray.prototype.set = function(pos, value){
            if (value == 1)
                this.field[~~(pos/BitArray.INT_WIDTH)] |= 1 << (pos % BitArray.INT_WIDTH);
            else if(this.field[~~(pos/BitArray.INT_WIDTH)] & 1 << (pos % BitArray.INT_WIDTH))
                this.field[~~(pos/BitArray.INT_WIDTH)] ^= 1 << (pos % BitArray.INT_WIDTH);
        }

        // Read a bit (1/0)
        BitArray.prototype.get = function(pos){
            return (this.field[~~(pos/BitArray.INT_WIDTH)] & 1 << (pos % BitArray.INT_WIDTH)) > 0 ? 1 : 0;
        }
        
        //clear all
        BitArray.prototype.clear = function () {
            for (var i = 0; i < this.field.length; i++) {
                this.field[i] = 0;
            }
        }
        
        // Iterate over each bit
        BitArray.prototype.each = function(method){
            for (var index = 0; index < this.size; index++) method(this.get(index), index);
        }

        // Returns the field as a string like "0101010100111100," etc.
        BitArray.prototype.toString = function(){
            var string = this.field.map(function(ea){
                var binary = ea.toString(2);
                binary = (new Array(BitArray.INT_WIDTH - binary.length + 1).join('0')) + binary;
                return binary;
            }).reverse().join('');
            return string.split('').reverse().join('').slice(0,this.size);
        }
        </script>
    </body>
</html>